#include <system/Thread.h>

namespace ne
{
    Thread::Thread(void *(*startRoutine)(void *), void *arg, const pthread_attr_t *attr)
        : mIsJoinable(true),
          mIsRunning(true),
          mIsFinished(false),
          mRoutine(startRoutine),
          mArg(arg)
    {
        MutexLocker locker(&mMutex);
        pthread_create(&mThread, attr, _Routine, this);
    }

    ThreadID Thread::getID() const
    {
        MutexLocker locker(&mMutex);
        return mThread;
    }

    bool Thread::joinable() const
    {
        MutexLocker locker(&mMutex);
        return mIsJoinable;
    }

    bool Thread::isRunning() const
    {
        MutexLocker locker(&mMutex);
        return mIsRunning;
    }

    bool Thread::isFinished() const
    {
        MutexLocker locker(&mMutex);
        return mIsFinished;
    }

    bool Thread::equal(const Thread &thread) const
    {
        MutexLocker locker(&mMutex);
        if (pthread_equal(mThread, thread.getID()))
        {
            return true;
        }
        return false;
    }

    bool Thread::detach()
    {
        if (!joinable()) return false;

        MutexLocker locker(&mMutex);
        if (pthread_detach(mThread))
        {
            return false;
        }

        mIsJoinable = false;

        return true;
    }

    bool Thread::join(void **threadReturn)
    {
        if (!joinable()) return false;

        MutexLocker locker(&mMutex);
        if (pthread_join(mThread, threadReturn))
        {
            return false;
        }

        mIsJoinable = false;

        return true;
    }

    bool Thread::kill(int returnValue)
    {
        if (!joinable()) return false;

        MutexLocker locker(&mMutex);
        if (pthread_kill(mThread, returnValue))
        {
            return false;
        }

        mIsJoinable = false;
        mIsRunning = false;

        return true;
    }
    
    /*
    bool Thread::cancel()
    {
        if (!joinable()) return false;

        MutexLocker locker(&mMutex);
        if (pthread_cancel(mThread))
        {
            return false;
        }

        mIsJoinable = false;
        mIsRunning = false;

        return true;
    }

    void Thread::exit(void *returnValue)
    {
        if (!joinable()) return;

        MutexLocker locker(&mMutex);
        if (pthread_equal(mThread, pthread_self()))
        {
            mIsRunning = false;
            mIsFinished = true;
            pthread_exit(returnValue);
        }
    }
    */

    Thread::~Thread()
    {
        kill(0);
    }

    void* Thread::_Routine(void *arg)
    {
        Thread *pThread = reinterpret_cast<Thread*>(arg);
        void *returnValue = pThread->mRoutine(pThread->mArg);

        MutexLocker locker(&(pThread->mMutex));
        pThread->mIsRunning = false;
        pThread->mIsFinished = true;
        return returnValue;
    }
}
